package me.weijing.common.xmpp;

import java.io.IOException;
import java.io.StringReader;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import me.weijing.common.otr.OtrException;
import me.weijing.common.otr.SessionID;
import me.weijing.common.xmpp.aidl.IChat;
import me.weijing.common.xmpp.aidl.IMessageListener;
import me.weijing.common.xmpp.service.Contact;
import me.weijing.common.xmpp.service.Message;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.ChatState;
import org.jivesoftware.smackx.ChatStateListener;
import org.jivesoftware.smackx.receipts.DeliveryReceipt;
import org.jivesoftware.smackx.receipts.DeliveryReceiptManager;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

/**
 * An adapter for smack's Chat class.
 * 
 * @author darisk
 */
public class ChatAdapter extends IChat.Stub {
    private static final int HISTORY_MAX_SIZE = 50;
    private static final String TAG = "ChatAdapter";
    private static final String PROTOCOL = "XMPP";
    private final Chat mAdaptee;
    private final Contact mParticipant;
    private String mState;
    private boolean mIsOpen;
    private final List<Message> mMessages;
    private final RemoteCallbackList<IMessageListener> mRemoteListeners = new RemoteCallbackList<IMessageListener>();
    private final MsgListener mMsgListener = new MsgListener();
    private SessionID mOtrSessionId;
    private String mAccountUser;
    private XmlPullParser parser;
    private final XMPPConnection mConnection;

    /**
     * 构造函数初始化数据
     * 
     * @param chat
     * @param mConnection
     */
    public ChatAdapter(final Chat chat, XMPPConnection mConnection) {
        mAdaptee = chat;
        mParticipant = new Contact(chat.getParticipant());
        mMessages = new LinkedList<Message>();
        mAdaptee.addMessageListener(mMsgListener);
        this.mConnection = mConnection;
        try {
            parser = XmlPullParserFactory.newInstance().newPullParser();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
    }

    /**
     * 得到Contact
     */
    @Override
    public Contact getParticipant() throws RemoteException {
        return mParticipant;
    }

    /**
     * 发送消息
     */
    @Override
    public void sendMessage(Message message) throws RemoteException {
        if (!mConnection.isAuthenticated())
            throw new RemoteException();
        transferMessage(message);
    }

    /**
     * 转换消息
     * 
     * @param message
     */
    private void transferMessage(Message message) {
        org.jivesoftware.smack.packet.Message send = new org.jivesoftware.smack.packet.Message();
        String msgBody = message.getBody();
        send.setTo(message.getTo());
        Log.w(TAG, "message to " + message.getTo());
        send.setBody(msgBody);

        send.setThread(message.getThread());
        send.setSubject(message.getSubject());
        send.setType(org.jivesoftware.smack.packet.Message.Type.chat);
        DeliveryReceiptManager.addDeliveryReceiptRequest(send);
        Log.i("TAG", send.toXML());
        try {
            mAdaptee.sendMessage(send);
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息
     * 
     * @param msg
     */
    public void injectMessage(String msg) {
        Message msgToSend = new Message(mParticipant.getJIDWithRes(), Message.MSG_TYPE_CHAT);
        msgToSend.setBody(msg);
        transferMessage(msgToSend);
    }

    /**
     * 增加监听
     */
    @Override
    public void addMessageListener(IMessageListener listen) {
        if (listen != null)
            mRemoteListeners.register(listen);
    }

    /**
     * 移除监听
     */
    @Override
    public void removeMessageListener(IMessageListener listen) {
        if (listen != null) {
            mRemoteListeners.unregister(listen);
        }
    }

    /**
     * 获取状态
     */
    @Override
    public String getState() throws RemoteException {
        return mState;
    }

    /**
     * 设置状态
     */
    @Override
    public void setState(String state) throws RemoteException {
        mState = state;
    }

    /**
     * 获取Chat
     * 
     * @return
     */
    public Chat getAdaptee() {
        return mAdaptee;
    }

    /**
     * 开启Chat
     */
    @Override
    public void setOpen(boolean isOpen) {
        this.mIsOpen = isOpen;
    }

    /**
     * 判断是否开启Chat
     */
    @Override
    public boolean isOpen() {
        return mIsOpen;
    }

    /**
     * 获取消息
     */
    @Override
    public List<Message> getMessages() throws RemoteException {
        return Collections.unmodifiableList(mMessages);
    }

    /**
     * 将消息添加到集合里
     * 
     * @param msg
     */
    private void addMessage(Message msg) {
        if (mMessages.size() == HISTORY_MAX_SIZE)
            mMessages.remove(0);
        mMessages.add(msg);
    }

    /**
     * 获取Message的监听
     */
    private class MsgListener implements ChatStateListener {
        public MsgListener() {
        }

        @Override
        public void processMessage(Chat chat, org.jivesoftware.smack.packet.Message message) {
            if (message == null) {
                return;
            }
            String xml = message.toXML();
            try {
                try {
                    if (parsexml(xml)) {
                        return;
                    }
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            final Message msg = new Message(message);
            ChatAdapter.this.addMessage(msg);
            try {
                final int n = mRemoteListeners.beginBroadcast();
                for (int i = 0; i < n; i++) {
                    IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
                    if (listener != null)
                        listener.processMessage(ChatAdapter.this, msg);
                }
            } catch (RemoteException e) {
                Log.w(TAG, "Error while diffusing message to listener", e);
            }

            mRemoteListeners.finishBroadcast();
        }

        @Override
        public void stateChanged(Chat chat, ChatState state) {
            mState = state.name();
            final int n = mRemoteListeners.beginBroadcast();

            for (int i = 0; i < n; i++) {
                IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
                try {
                    listener.stateChanged(ChatAdapter.this);
                } catch (RemoteException e) {
                    Log.w(TAG, e.getMessage());
                }
            }
            mRemoteListeners.finishBroadcast();
        }

    }

    @Override
    public int getUnreadMessageCount() throws RemoteException {

        return 0;
    }

    /**
     * 解析xml判断是否含有命名空间urn:xmpp:receipts，如果有就跳出
     * 
     * @param xml
     * @return
     * @throws IOException
     * @throws XmlPullParserException
     */
    public boolean parsexml(String xml) throws IOException, XmlPullParserException {
        parser.setInput(new StringReader(xml));
        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            switch (eventType) {
            case XmlPullParser.START_DOCUMENT:
                break;
            case XmlPullParser.START_TAG:
                if (parser.getName().equals("received")) {
                    Log.i("TAG", parser.getAttributeValue("", "xmlns"));
                    if (parser.getAttributeValue("", "xmlns").equals(DeliveryReceipt.NAMESPACE)) {
                        return true;
                    }
                }
                break;
            case XmlPullParser.END_TAG:
                break;

            }
            eventType = parser.next();
        }
        return false;
    }

    @Override
    public void startOtrSession() throws RemoteException {

    }

    @Override
    public void endOtrSession() throws RemoteException {

    }

    @Override
    public String getLocalOtrFingerprint() throws RemoteException {

        return null;
    }

    @Override
    public String getRemoteOtrFingerprint() throws RemoteException {

        return null;
    }

    @Override
    public void verifyRemoteFingerprint(boolean ok) throws RemoteException {

    }

    @Override
    public String getOtrStatus() throws RemoteException {

        return null;
    }

    public boolean localEndOtrSession() throws OtrException {
        if (mOtrSessionId == null)
            return true;

        BeemOtrManager.getInstance().getOtrManager().endSession(mOtrSessionId);
        BeemOtrManager.getInstance().removeChat(mOtrSessionId);
        mOtrSessionId = null;
        listenOtrSession();
        return true;
    }

    public void listenOtrSession() {
        if (mOtrSessionId != null)
            return;

        mOtrSessionId = new SessionID(mAccountUser, mParticipant.getJIDWithRes(), PROTOCOL);
        BeemOtrManager.getInstance().addChat(mOtrSessionId, this);
        BeemOtrManager.getInstance().getOtrManager().getSessionStatus(mOtrSessionId);
    }
}
